"""
Copyright (c) 2022 Huawei Technologies Co.,Ltd.

openGauss is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:

          http://license.coscl.org.cn/MulanPSL2

THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
"""
"""
Case Type   : 故障&可靠性测试
Case Name   : 主节点数据恢复过程中，主节点磁盘不足
Create At   : 2020/07/25
@zou_jialiang0505328126
Description :
    1.主节点进行数据恢复
    2.数据恢复过程中，主节点注入磁盘满故障
    3.查看数据恢复结果
    4.清除故障，重启数据库
    5.查询数据库状态
    6.再次进行数据恢复
Expect      :
    1.主节点开始进行数据恢复
    2.数据恢复过程中，主节点注入磁盘满故障成功
    3.查看数据恢复结果失败
    4.清除故障，重启数据库成功
    5.查询数据库状态正常
    6.再次进行数据恢复成功
History     :
    modified：2021-3-5 by 5328113;修改restore失败断言，及整个用例逻辑
"""
import os
import time
import unittest

from testcase.utils.ComThread import ComThread
from testcase.utils.Common import Common
from testcase.utils.CommonSH import *
from testcase.utils.Constant import Constant
from testcase.utils.Logger import Logger
from yat.test import Node
from yat.test import macro


class Disk_full(unittest.TestCase):
    nodes_tuple = ('PrimaryDbUser', 'Standby1DbUser', 'Standby2DbUser')

    @RestartDbCluster(*nodes_tuple)
    def setUp(self):
        self.log = Logger()
        self.log.info('----Opengauss_Reliability_Dbsys_Case134:初始化----')
        self.pri_dbuser = Node(node='PrimaryDbUser')
        self.pri_root = Node(node='PrimaryRoot')
        self.pri_sh = CommonSH('PrimaryDbUser')
        self.sta_1_sh = CommonSH('Standby1DbUser')
        self.constant = Constant()
        self.common = Common()
        self.dump_file_name = 'test_pid.tar'
        self.parent_path = os.path.dirname(macro.DB_INSTANCE_PATH)
        self.dump_file = os.path.join(self.parent_path,
                                      self.dump_file_name)

        self.log.info("-----创建restore数据库----")
        self.new_db_name = 'restore_db'
        self.create_db_cmd = f'drop database if exists {self.new_db_name};' \
            f'create database {self.new_db_name};'
        self.drop_db_cmd = f'drop database {self.new_db_name};'
        create_db_result = self.pri_sh.executDbSql(self.create_db_cmd)
        self.log.info(create_db_result)
        self.assertIn(self.constant.CREATE_DATABASE_SUCCESS_MSG,
                      create_db_result)

    def test_disk_full(self):
        self.log.info('----启动TPCC----')
        result = self.common.startTPCC(self.pri_root, macro.TPCC_PATH)
        self.log.info(result)
        self.assertIn(self.constant.TPCC_SUCCESS_MSG, result)

        self.log.info('----查看主机query，同步是否正常----')
        self.pri_sh.check_location_consistency('primary', 3)

        self.log.info('----查询主备状态----')
        status = self.pri_sh.getDbClusterStatus('status')
        self.assertTrue(status)

        self.log.info('----进行gs_dump----')
        dump_result = self.pri_sh.dumpFile(self.dump_file,
                                           get_detail=False)
        self.log.info(dump_result)
        self.assertTrue(dump_result)

        self.log.info('----进行gs_restore----')
        restore_thread = ComThread(self.pri_sh.restoreFile,
                                   args=(self.dump_file,
                                         '',
                                         True,
                                         self.new_db_name,))
        restore_thread.setDaemon(True)
        restore_thread.start()
        time.sleep(3)

        self.log.info('----注入磁盘满故障----')
        self.log.info("-----------获取主机磁盘信息 -----------")
        df_cmd = f"df -h {macro.DB_INSTANCE_PATH}"
        self.log.info(df_cmd)
        df_result = self.pri_root.sh(df_cmd).result()
        self.log.info(df_result)
        self.DISK_NAME = df_result.splitlines()[-1].split()[0].strip()

        self.log.info("-----------注入磁盘满故障 -----------")
        inject_cmd = f'rfile_full (diskname) values ({self.DISK_NAME})'
        inject_result = self.common.cfe_inject(self.pri_root, inject_cmd)
        self.log.info(inject_result)
        success_msg = self.constant.CFE_DISK_FULL_SUCCESS_MSG
        self.assertIn(success_msg, inject_result)

        self.log.info("-----------获取主机磁盘占用情况 -----------")
        df_cmd = f"df -h {macro.DB_INSTANCE_PATH}"
        self.log.info(df_cmd)
        df_result = self.pri_root.sh(df_cmd).result()
        self.log.info(df_result)
        self.USED_PERCENT = df_result.splitlines()[-1].split()[4].strip()
        self.assertTrue(self.USED_PERCENT == '100%')

        self.log.info('----等待10S，查询主备状态----')
        time.sleep(10)
        self.sta_1_sh.getDbClusterStatus('status')

        restore_thread.join(60 * 30)
        restore_result = restore_thread.get_result()
        self.assertIn(self.constant.RESTORE_FAIL_MSG, restore_result)

        time.sleep(10)
        self.log.info("-----------清除磁盘满故障 -----------")
        clean_cmd = f'rfile_full where(diskname={self.DISK_NAME})'
        clean_result = self.common.cfe_clean(self.pri_root, clean_cmd)
        self.log.info(clean_result)
        self.assertIn(self.constant.CFE_DISK_CLEAN_SUCCESS_MSG,
                      clean_result)
        self.log.info("-----------获取主机磁盘占用情况 -----------")
        df_cmd = f"df -h {macro.DB_INSTANCE_PATH}"
        self.log.info(df_cmd)
        df_result = self.pri_root.sh(df_cmd).result()
        self.log.info(df_result)
        self.USED_PERCENT = df_result.splitlines()[-1].split()[4].strip()
        self.assertTrue(self.USED_PERCENT != '100%')

        self.log.info('----重启数据库----')
        self.pri_sh.startDbCluster()

        self.log.info('----查看主机query，同步是否正常----')
        self.pri_sh.check_location_consistency('primary', 3)

        self.log.info('----查询主备状态----')
        status = self.pri_sh.getDbClusterStatus('status')
        self.assertTrue(status)

        self.log.info('----再次进行restore----')
        self.log.info('----刪除之前的restore库----')
        drop_db_result = self.pri_sh.executDbSql(self.drop_db_cmd)
        self.log.info(drop_db_result)
        self.assertIn(self.constant.drop_database_success_msg,
                      drop_db_result)
        self.log.info('----创建restore库----')
        create_db_result = self.pri_sh.executDbSql(self.create_db_cmd)
        self.log.info(create_db_result)
        self.assertIn(self.constant.CREATE_DATABASE_SUCCESS_MSG,
                      create_db_result)

        self.log.info('----再次进行restore----')
        restore_result = self.pri_sh.restoreFile(self.dump_file,
                                                 '',
                                                 True,
                                                 self.new_db_name)
        self.assertNotIn(self.constant.RESTORE_FAIL_MSG, restore_result)

        self.log.info('----同步是否正常----')
        self.pri_sh.check_location_consistency('primary', 3)

        self.log.info('----查询主备状态----')
        status = self.pri_sh.getDbClusterStatus('status')
        self.assertTrue(status)

    def tearDown(self):
        self.log.info('----this is tearDown----')
        self.log.info('----删除tar文件----')
        self.pri_dbuser.sh(f'rm -rf {self.dump_file}').result()
        ls_cmd = f'ls -l {self.dump_file}'
        self.log.info(self.pri_dbuser.sh(ls_cmd).result())

        self.log.info("----删除restore库----")
        drop_db_result = self.pri_sh.executDbSql(self.drop_db_cmd)
        self.log.info(drop_db_result)

        df_cmd = f"df -h {macro.DB_INSTANCE_PATH}"
        self.log.info(df_cmd)
        df_result = self.pri_root.sh(df_cmd).result()
        self.log.info(df_result)
        self.USED_PERCENT = df_result.splitlines()[-1].split()[4].strip()
        if self.USED_PERCENT == '100%':
            self.log.info('----异常中断，磁盘故障未恢复处理----')
            clean_disk_cmd = f'rfile_full  where(diskname={self.DISK_NAME})'
            clean_disk_result = self.common.cfe_clean(self.pri_root,
                                                      clean_disk_cmd)
            self.log.info(clean_disk_result)

        self.log.info('----校验刷脏页是否完成----')
        self.pri_sh.check_whether_remain_dirty_page()
